package db

import (
	"errors"
	"github.com/jackc/pgx"
	"strings"
)

var DB *pgx.Conn

func InitDb(dataSourceName string) (err error) {
	if !strings.Contains(dataSourceName, "sslmode") {
		dataSourceName += " sslmode=disable"
	}

	conf, err := pgx.ParseDSN(dataSourceName)
	if err != nil {
		return err
	}
	DB, err = pgx.Connect(conf)
	if err != nil {
		return err
	}

	return err
}

//

type Catalogue struct {
	Id   int32
	Name string
	Sort int32
	Show bool
}

func SaveOrGetCatalogue(name string) int32 {
	save := `
insert into catalogue (id, name)
values ((select COALESCE(max(id), 0) + 1 from catalogue), $1)
on conflict (name) do update set sort = catalogue.sort + 1
    returning id
`
	var id int32
	er := DB.QueryRow(save, name).Scan(&id)
	if er != nil {
		throwException(er)
	}

	return id
}

type Article struct {
	Id          int64
	Title       string
	Cover       string
	Description string
	Tags        []string
	CatalogueId int32
	PublishedAt string
	SourceUrl   string
	SourceName  string
	Content     string

	Catalogue string
}

// ListArticle 文章列表

func ListArticle(limit, lastId int) (articles []*Article) {
	query := `
select id,title,cover,description,to_char(published_at,'YYYY-MM-DD') published_at,source_name,source_url,tags,
(select c.name from catalogue c where c.id=catalogue_id) catalogue
from article 
where id > $2
order by id desc 
limit $1
`
	rows, er := DB.Query(query, limit, lastId)
	throwException(er)

	for rows.Next() {
		a := &Article{}
		er := rows.Scan(&a.Id, &a.Title, &a.Cover, &a.Description, &a.PublishedAt, &a.SourceName, &a.SourceUrl,
			&a.Tags, &a.Catalogue, )
		throwException(er)

		articles = append(articles, a)
	}

	return articles
}

//
func GetArticle(id int64) *Article {
	get := `
select id,title,cover,description,to_char(published_at,'YYYY年MM月DD日') published_at,source_name,source_url,tags,
(select c.name from catalogue c where c.id=catalogue_id) catalogue
from article 
where id = $1
`
	a := &Article{}
	row := DB.QueryRow(get, id, )
	er := row.Scan(&a.Id, &a.Title, &a.Cover, &a.Description, &a.PublishedAt, &a.SourceName, &a.SourceUrl,
		&a.Tags, &a.Catalogue, )
	if er == pgx.ErrNoRows {
		return nil
	} else {
		throwException(er)
	}

	return a
}

func CheckSource(sourceUrl string) bool {
	check := `
select exists(select 1 from article where source_url = $1) e
`
	var e bool
	DB.QueryRow(check, sourceUrl).Scan(&e)
	return e
}

func InsertArticle(a *Article) (id int64) {
	insert := `
insert into article (title, cover, description, catalogue_id, tags, published_at, content, source_url, source_name)
values ($1, $2, $3, $4, $5, $6, $7, $8, $9)
returning id
`
	row := DB.QueryRow(insert, &a.Title, &a.Cover, a.Description, a.CatalogueId, a.Tags, a.PublishedAt,
		a.Content, a.SourceUrl, a.SourceName)
	er := row.Scan(&id)
	throwException(er)

	return id
}

func SaveArticle(a *Article) {
	if "" == a.SourceUrl {
		throwException(errors.New("article source url can not be empty"))
	}
	if CheckSource(a.SourceUrl) {
		return
	}
	if "" != a.Catalogue {
		a.CatalogueId = SaveOrGetCatalogue(a.Catalogue)
	}
	InsertArticle(a)
}

//

type User struct {
	Id       int
	Username string
	Password string

	Email    string
	WxOpenid string
	QQ       string
	WeiboUid string

	CreatedAt     string
	LatestLoginAt string
}

//

func throwException(err error) {
	if err != nil {
		panic(err)
	}
}
